package Hangman;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import net.miginfocom.swing.MigLayout;
/**
 * HangmanGame class
 * Handles the game components in multiple JPanels with lots of different
 * components, and handles all game logic besides the Menu system (Settings inc.)
 * @author Robin E, Jakob L, Isac A, Cristian O, Eric P, Tobias W. 
 *
 */

@SuppressWarnings("serial")
public class HangmanGame extends JPanel{
	
	// Game panels
	private JPanel gameWindow;
	private JPanel interfaceWindow;
	private JPanel playerPanel;
	
	// Components
	// Player labels
	private JLabel player1;
	private JLabel player2;
	private JLabel player3;
	// Other components
	private JLabel playerHeadline; // Simply the headline for players
	private JLabel dynamicGuesses; 
	private JLabel guessesMade; // The guesses the player/s have guessed.
	private JLabel nrOfFailsLabel;
	private JLabel dynamicfailedLabel; // How many tries you have left
	private JLabel wordToGuess; // The word in question
	private JLabel guessLabel;
	private JLabel imageHolder;
	
	private JTextField guessTextField;
	private JButton guessButton;
	private JButton clearButton;
	
	private BufferedImage img;
	
	private Sound sound=new Sound(null);
	
	private FileLoader fileLoader;
	
	private Word chosenWord;
	private Word playerWord;
	
	private String difficulty = "";
	private int difficultyCurve;
	
	private Font mediumFont;
	
	private boolean won;
	
	private Player[] playersArray;
	
	private JLabel[] labels;
	
	private Player currentPlayer;
	
	/**
	 * HangmanGame Contructor, initializes all components in the class.
	 * Also adds all components to their respective JPanel.
	 */
	HangmanGame()
	{
		setLayout(new BorderLayout());
		
		labels = new JLabel[3];
		
		Font largeFont = new Font("Arial", Font.BOLD, 30);
		mediumFont = new Font("Arial", Font.BOLD, 18);
		fileLoader = new FileLoader();
		
		gameWindow = new JPanel(); // To hold the ever changing image
		gameWindow.setBackground(Color.white);
		
		try{
			img = ImageIO.read(new File("Images\\hangmanimage1.png"));
		}catch(IOException e){ e.printStackTrace();}
		
		imageHolder = new JLabel();
		imageHolder.setIcon(new ImageIcon(img));
		gameWindow.add(imageHolder);
		
		interfaceWindow = new JPanel(); // To hold the guessed letters/Errors etc
		interfaceWindow.setBackground(Color.white);
		interfaceWindow.setLayout(new MigLayout());
		
		wordToGuess = new JLabel();
		
		nrOfFailsLabel = new JLabel("Tries left: ");
		
		dynamicfailedLabel = new JLabel("X");
			
		dynamicGuesses = new JLabel("Guesses: ");
		guessesMade = new JLabel("");
		guessLabel = new JLabel("Guess:");
		guessTextField = new JTextField(30);
		
		guessTextField.addActionListener(new keyL());
		guessButton = new JButton("Guess");
		guessButton.addMouseListener(new guessListener());
		clearButton = new JButton("Clear");
		clearButton.addMouseListener(new clearListener());
		
		player1 = new JLabel("");
		player2 = new JLabel("");
		player3 = new JLabel("");
		
		labels[0] = player1;
		labels[1] = player2;
		labels[2] = player3;
				
		interfaceWindow.add(nrOfFailsLabel, "gapbefore 160");
		interfaceWindow.add(dynamicfailedLabel, "gapafter 200");
		interfaceWindow.add(new JLabel("Word: "));
		interfaceWindow.add(wordToGuess);
		interfaceWindow.add(new JLabel(""), "wrap");
		interfaceWindow.add(dynamicGuesses, "gapbefore 160");
		interfaceWindow.add(guessesMade);
		interfaceWindow.add(new JLabel(""), "wrap");
		
		interfaceWindow.add(guessLabel, "gapbefore 160");
		interfaceWindow.add(guessTextField);
		interfaceWindow.add(guessButton);
		interfaceWindow.add(clearButton);	
		
		playerPanel = new JPanel(); // To hold the players
		playerPanel.setBackground(Color.white);
		playerPanel.setLayout(new MigLayout());
		
		playerHeadline = new JLabel("Players");
		playerHeadline.setFont(largeFont);
		
		playerPanel.add(new JLabel(""), "wrap 20");
		playerPanel.add(new JLabel(""), "gapbefore 20");
		playerPanel.add(playerHeadline, "gapafter 20");
		playerPanel.add(new JLabel(""), "wrap");
		playerPanel.add(player1, "gapbefore 10");
		playerPanel.add(new JLabel(""), "wrap");
		playerPanel.add(player2, "gapbefore 10");
		playerPanel.add(new JLabel(""), "wrap");
		playerPanel.add(player3, "gapbefore 10");
	}
	/**
	 * init(), used to initialize the HangmanGame class
	 * Fetch all the game settings from FileLoader
	 */
	public void init()
	{
		fileLoader.updateSettings();
		fileLoader.generateList();
		
		difficulty = fileLoader.getDifficulty();
		
		chosenWord = fileLoader.getRandomWord();
		
		playersArray = new Player[Integer.parseInt(fileLoader.getPlayersAmount())];		
		
		switch(difficulty)
		{
		case "Easy": difficultyCurve = 10; break;
		case "Medium": difficultyCurve = 7; break;
		case "Hard": difficultyCurve = 5; break;
		case "Extreme": difficultyCurve = 2; break;
		}
		
		add(gameWindow, BorderLayout.CENTER);
		add(interfaceWindow, BorderLayout.SOUTH);
		
		// Check if the number of players is more than 1.
		if(playersArray.length > 1)
		{
			// If it is, activate "Multiplayer" and ask for the players name
			for(int i = 0; i < playersArray.length; i++)
			{
				String name = JOptionPane.showInputDialog("What is your name?");
				playersArray[i] = new Player(name);
				
				labels[i].setText(name);
			}
			// Iterate through the players and set each players next pointer to their next
			// player in the order
			for(int j = 0; j < playersArray.length; j++)
			{
				int nextIndex = j+1;
				
				if(!(nextIndex > playersArray.length-1))
				{
					playersArray[j].setNextPlayer(playersArray[nextIndex]);
				}
				else
				{
					playersArray[j].setNextPlayer(playersArray[1]);
				}
			}
			currentPlayer = playersArray[1];
			boolean stringOK = false;
			
			do
			{
				// Ask the first player to choose a word the other player/s need to guess.
				String playerChosenWord = JOptionPane.showInputDialog(playersArray[0].getName() + ", Please type the specific word or phrase the other players should guess");
				
				// Check whether the word the player has written is actually not null and not a single space
				if(playerChosenWord != null && !(playerChosenWord.equalsIgnoreCase("")) && !(playerChosenWord.equalsIgnoreCase(" ")))
				{
					// Transform the player chosen word to lower case letters.
					playerChosenWord=playerChosenWord.toLowerCase();
					Letter[] lettersInWord = new Letter[playerChosenWord.length()];
					String[] stringArray = playerChosenWord.split("");
				
					for(int index = 0; index < playerChosenWord.length(); index++)
					{
						lettersInWord[index] = new Letter(stringArray[index]);
					}
					
					playerWord = new Word(lettersInWord);
					
					// Set the label to the chosen word by calling toString() of the specific Word object
					wordToGuess.setText(playerWord.toString());
					
					stringOK = true;
				}
				else
				{
					stringOK = false;
				}
				
			}while(stringOK == false);
			
			JOptionPane.showMessageDialog(null, currentPlayer.getName() + "'s turn");
		}
		else
		{
			// Activate Single player game and randomly use a word from the selected theme in the FileLoader.
			wordToGuess.setText(chosenWord.toString());
		}
		
		
		add(playerPanel, BorderLayout.WEST);
		dynamicfailedLabel.setText(""+difficultyCurve);
		// Change the font to be of a larger calibrer
		wordToGuess.setFont(mediumFont);
		
	}
	
	/**
	 * hideWindow() is a simple method to hide this JPanel
	 */
	public void hideWindow()
	{
		setVisible(false);
	}
	/**
	 * showWindow() is a simple method to show the JPanel and set the size of the JPanel.
	 */
	public void showWindow()
	{
		setSize(1000, 800);
		setVisible(true);
	}
	/**
	 * guess(), used to guess a character from the textfield
	 */
	public void guess()
	{
		// Split the information(String) from the textfield
		String[] guessedWord = guessTextField.getText().split("");
		String temp = guessesMade.getText();
		temp += guessedWord[0];
		
		String chosenWordShown = "";
		
		// Check whether single player or multiplayer mode is activated by checking how many players are playing
		if(playersArray.length <= 1)
		{
			for(int i = 0; i < chosenWord.getWord().length; i++)
			{
				chosenWordShown += chosenWord.getWord()[i].getLetterS();
			}
		}
		else
		{
			for(int i = 0; i < playerWord.getWord().length; i++)
			{
				chosenWordShown += playerWord.getWord()[i].getLetterS();
			}
		}
		
		// Check whether the word contains the specific character which is guessed.
		if(chosenWordShown.contains(guessedWord[0]) && ! (guessedWord[0].equalsIgnoreCase("")) && !(guessedWord[0].equalsIgnoreCase(" ")))
		{
			// Single player - go through the word and check where the character is equal to each other and turns the letter(Showing it).
			if(playersArray.length <= 1)
			{
				for(int j = 0; j < chosenWord.getWord().length; j++)
				{
					if(chosenWordShown.charAt(j) == guessedWord[0].charAt(0))
					{
						if(chosenWord.getWord()[j].getHidden() == true)
						{
							chosenWord.getWord()[j].turn();
							guessesMade.setText(temp);
							guessTextField.setText("");
						}
					}
				}
			}
			else // Multiplayer - go through the word and check where the character is equal to each other and turns the letter(Showing it).
			{
				for(int j = 0; j < playerWord.getWord().length; j++)
				{
					if(chosenWordShown.charAt(j) == guessedWord[0].charAt(0))
					{
						if(playerWord.getWord()[j].getHidden() == true)
						{
							playerWord.getWord()[j].turn();
							guessesMade.setText(temp);
							guessTextField.setText("");
						}
					}
				}
			}
			// Clear the textfield
			guessTextField.setText("");
			
		}
		else if(guessedWord[0].equalsIgnoreCase("") || (guessedWord[0].equalsIgnoreCase(" "))){
			guessTextField.setText("");
		}
		else
		{	
			// If more than 2 players, activate calls to next players and show current player for the user.
			if(playersArray.length>2)
			{
				currentPlayer = currentPlayer.getNextPlayer();
				JOptionPane.showMessageDialog(null, currentPlayer.getName() + "'s turn");
			}
			// Check if the character has already been guessed.
			if(guessesMade.getText().contains(guessedWord[0]))
			{
				guessTextField.setText("");
				JOptionPane.showMessageDialog(null, "You have already guessed on that one!");
			}
			else
			{	
				guessTextField.setText("");
				guessesMade.setText(temp);
				// If it is a new guess, decrese the number of guesses left depending on the difficulty
				difficultyCurve--;
				dynamicfailedLabel.setText(""+difficultyCurve);
				
				switch(difficultyCurve)
				{
				case 0:
				{
					paintImage("Images\\hangmanimage11.png");
					
					JOptionPane.showMessageDialog(null, "The word you where guessing on is: \"" + chosenWordShown + "\"");
					guessesMade.setText("");
					paintImage("Images\\hangmanimage1.png");
					// Reset the player labels and hide the JPanel.
					labels[0].setText("");
					labels[1].setText("");
					labels[2].setText("");
					setVisible(false);
					break;
				}
				case 1:
				{					
					paintImage("Images\\hangmanimage10.png");
					break;
				}
				case 2:
				{
					paintImage("Images\\hangmanimage9.png");
					break;
				}
				case 3:
				{
					paintImage("Images\\hangmanimage8.png");
					break;
				}
				case 4:
				{
					paintImage("Images\\hangmanimage7.png");
					break;
				}
				case 5:
				{
					paintImage("Images\\hangmanimage6.png");
					break;
				}
				case 6:
				{
					paintImage("Images\\hangmanimage5.png");
					break;
				}
				case 7:
				{
					paintImage("Images\\hangmanimage4.png");
					break;
				}
				case 8:
				{
					paintImage("Images\\hangmanimage3.png");
					break;
				}
				case 9:
				{
					paintImage("Images\\hangmanimage2.png");
					break;
				}
				case 10:
				{
					paintImage("Images\\hangmanimage1.png");
					break;
				}
				}
			}
		}
		// If players is only 1, set the random word, else set the player word
		if(playersArray.length > 1)
		{
			wordToGuess.setText(playerWord.toString());
		}
		else 
		{
			wordToGuess.setText(chosenWord.toString());
		}
		
		won = true;
		
		// Check whether the player has any more characters to guess of the word before everything is complete
		if(playersArray.length <= 1)
		{
			for(int letter = 0; letter < chosenWord.getWord().length; letter++)
			{
				if(chosenWord.getWord()[letter].getHidden() == true)
				{
					won = false;
					break;
				}
			}
		}
		else
		{
			for(int letter = 0; letter < playerWord.getWord().length; letter++)
			{
				if(playerWord.getWord()[letter].getHidden() == true)
				{
					won = false;
					break;
				}
			}
		}
		
		// If the word is complete, pop up message panel depending on single/multi- player mode.
		if(won == true)
		{
			if(playersArray.length>1)
			{
				JOptionPane.showMessageDialog(null, "Congratulations! You won! " + currentPlayer.getName() + ".");
			}
			else
			{
				JOptionPane.showMessageDialog(null, "Congratulations! You won!.");
			}
			
			// Reset every field and the player labels
			guessesMade.setText("");
			paintImage("Images\\hangmanimage1.png");
			labels[0].setText("");
			labels[1].setText("");
			labels[2].setText("");
			setVisible(false);
		}
		
	}
	/**
	 * paintImage(String fileName) is used to paint a specific image on the JLabel which holds the image
	 * @param fileName which path to the image file
	 */
	private void paintImage(String fileName)
	{
		try
		{
			img = ImageIO.read(new File(fileName));
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
		
		imageHolder.setIcon(new ImageIcon(img));
	}
	
	/**
	 * clearListener is a listener inner class which is used by the button clearButton
	 * Holds two different states where the mouse cursor is changed and when
	 * the mouse is released, the textField is cleared of all text.
	 * @author Robin E, Jakob L, Isac A, Cristian O, Eric P, Tobias W. 
	 *
	 */
	public class clearListener extends MouseAdapter
	{
		public void mouseEntered(MouseEvent mEntered)
		{
			Cursor c = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
			setCursor(c);
		}
		
		public void mouseExited(MouseEvent mExited)
		{
			Cursor c = Cursor.getDefaultCursor();
			setCursor(c);
		}
		
		public void mouseReleased(MouseEvent mReleased)
		{
			sound.beepPool("hangman-sounds/beep01.wav");
			guessTextField.setText("");
		}
	}
	/**
	 * guessListener is a listener inner class which is used by the button guessButton
	 * Holds two different states where the mouse cursor is changed and when
	 * the mouse is released, it calls the method guess.
	 * @author Robin E, Jakob L, Isac A, Cristian O, Eric P, Tobias W. 
	 *
	 */
	public class guessListener extends MouseAdapter
	{
		public void mouseEntered(MouseEvent mEntered)
		{
			Cursor c = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
			setCursor(c);
		}
		
		public void mouseExited(MouseEvent mExited)
		{
			Cursor c = Cursor.getDefaultCursor();
			setCursor(c);
		}
		
		public void mouseReleased(MouseEvent mReleased)
		{
			sound.beepPool("hangman-sounds/beep.wav");
			guess();
		}
		
	}	
	/**
	 * keyL is a listener inner class with the same function as guessListener except it
	 * doesnt hold states for changing the cursor in the game. Responds when the user types
	 * something in the textfield and presses 'Enter'.
	 * @author Robin E, Jakob L, Isac A, Cristian O, Eric P, Tobias W. 
	 *
	 */
	public class keyL implements ActionListener{
		
		@Override
		public void actionPerformed(ActionEvent ev){
			
			guess();
		}
	
	}
	
}
